<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<!--
npm install socket.io-client

cdnjs: https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.1.2/socket.io.min.js
jsDelivr: https://cdn.jsdelivr.net/npm/socket.io-client@4.1.2/dist/socket.io.min.js
unpkg: https://unpkg.com/socket.io-client@4.1.2/dist/socket.io.min.js

socket.io.js	34.7 kB gzip	Unminified version, with debug
socket.io.min.js	14.7 kB min+gzip	Production version, without debug
socket.io.msgpack.min.js	15.3 kB min+gzip	Production version, without debug and with the msgpack parser

关于 msgpack parser: https://github.com/socketio/socket.io-msgpack-parser
默认 socket.io-parser 的替代方案，使用 msgpack 编码和解码数据包。
使用该解析器，浏览器构建会更重一些（额外压缩 7.5 KB，压缩 3.0 KB），但每条消息会更小（以二进制形式发送）。
请注意，您必须在双方（服务器和客户端）上使用解析器。
-->
<!--<script src="https://cdn.socket.io/4.1.2/socket.io.min.js" integrity="sha384-toS6mmwu70G0fw54EGlWWeA4z3dyJ+dlXBtSURSKN4vyRFOcxd3Bzjj/AoOwY+Rg" crossorigin="anonymous"></script>-->
<script src="https://unpkg.com/socket.io-client@4.1.2/dist/socket.io.js"></script>
<script>
  //During development, we recommend using the socket.io.js bundle. By setting localStorage.debug = 'socket.io-client:socket', any event received by the client will be printed to the console.
  //todo 没用？
  localStorage.debug = 'socket.io-client:socket';

  // emmm 不像websocket, socket.io 默认是不支持跨域的 :
  // Access to XMLHttpRequest at 'http://localhost:3000/socket.io/?EIO=4&transport=polling&t=NkXdXKW' from origin 'http://localhost:63342' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
  const socket = io(
    "ws://localhost:3000",
    {
      reconnection: false,
      timeout: 5000, //默认值 2000
      autoConnect: false  //默认为true
      /*
        设置为false后, 就需要以下这样连接
        socket.connect();
        // or
        socket.io.open();
      */
    }
  );

  // socket.connect()

  console.log('socket.io.open:',socket.io.open.toString());
  // socket.io.open 打开的不会触发 socket.on('connect') 等事件？
  socket.io.open((err)=>{
    console.log('err:',err);
    if(!err) socket.connect();
  });

  const tryReconnect = () => {
    console.log('5秒后重连');
    setTimeout(() => {
      //<del>socket.io.open 等价于 socket.connect();</del>
      console.log('--- --- --- 重连 --- --- ---');
      socket.io.open((err) => {
        if (err) {
          console.log('socket.io.open err --- --- ---');
          tryReconnect();
          //todo emit event, notify others --- xxx秒后重连
        }
      });
    }, 1000 * 5);
  }
  socket.on("disconnect", () => {
    console.log('disconnect--- --- ---');
    tryReconnect()
  });

  //todo emmm 客户端有些事件是方在socket.上的 有些是放在socket.io上的
  // socket.io上的: https://socket.io/docs/v4/client-api/#Event-%E2%80%98error%E2%80%99
  // socket上的: https://socket.io/docs/v4/client-api/#Event-%E2%80%98connect%E2%80%99
  //
  //注意和 服务端的 进行区分, 服务端和客户端的事件类型并不一样 (服务端也分io上的和socket上的,并且还多了个engine):
  // io: https://socket.io/docs/v4/server-api/#Event-connection
  // socket: https://socket.io/docs/v4/server-api/#Event-%E2%80%98disconnect%E2%80%99
  // engine: https://socket.io/docs/v4/server-api/#Event-%E2%80%98initial-headers%E2%80%99
  //
  //connection timeout before an error event is emitted
  //这个事件会比 socket.io.open err 先触发
  // <del>比较鸡肋, 因为我们可以在  socket.io.open 触发时对err进行判断 就能知道是否连接成功了</del>>
  // 第一次是autoConnect的话, 还是有用的, 第一次自动连接失败, 只有这里能监听到
  // 但其实你不如 直接把autoConnect关了, 要不这样要在两个地方处理错误 (socket.io.on('error')和socket.io.open(err=>{})), 这很可能导致你的业务逻辑会多执行一次
  /*socket.io.on("error", (error) => {
    console.log('socket.io error--- --- ---');
    // ...
  });*/


  socket.on("connect", () => {
    console.log('--- --- ---socket.on connect--- --- ---');

    // either with send()
    // 使用send发送的消息 对端固定使用 on message 来接受
    // 发送的类型不止字符串 也可以是个对象(json) 或则 buffer
    socket.send("Hello!");

    // or with emit() and custom event names
    // 不像.send, .emit能够自定义 对端 需要监听的事件类型
    socket.emit("salutations", "Hello!", { "mr": "john" }, Uint8Array.from([1, 2, 3, 4]));
  });

  // handle the event sent with socket.send()
  socket.on("message", data => {
    console.log('--- --- ---socket.on message--- --- ---');
    console.log(data);
  });

  // handle the event sent with socket.emit()
  socket.on("greetings", (elem1, elem2, elem3) => {
    console.log('--- --- ---socket.on greetings--- --- ---');
    console.log(elem1, elem2, elem3);
    console.log(typeof elem1, typeof elem2, typeof elem3);
    //string object object
    //说明如果发送的是对象(json) 或则 buffer,
    //在底层都会帮我们解析好 变成对应的类型 不用我们手动解析
  });
</script>
</body>
</html>
